package com.ruizhong.integratedmediawithoutc.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruizhong.integratedmediawithoutc.config.DefaultAssetsPathProvider;
import com.ruizhong.integratedmediawithoutc.dao.TProgramMapper;
import com.ruizhong.integratedmediawithoutc.entity.TProgram;
import com.ruizhong.integratedmediawithoutc.entity.TProgramMaterial;
import com.ruizhong.integratedmediawithoutc.service.TProgramMaterialService;
import com.ruizhong.integratedmediawithoutc.service.TProgramService;
import com.ruizhong.integratedmediawithoutc.util.SRSUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class TProgramServiceImpl extends ServiceImpl<TProgramMapper, TProgram> implements TProgramService {

    @Autowired
    private TProgramMaterialService tProgramMaterialService;

    @Override
    public Integer addProgram(HashMap<String, Object> programInfo) {
        System.out.println(programInfo);
        TProgram tProgram = new TProgram();
        tProgram.setProgramName(programInfo.get("programname").toString());
        tProgram.setDemandWay((Integer) programInfo.get("demandWay"));
        tProgram.setProgramType(programInfo.get("programType").toString());
        // 定义日期时间格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 获取当前时间
        LocalDateTime now = LocalDateTime.now();
        // 格式化日期时间
        String formattedDateTime = now.format(formatter);
        tProgram.setSubmitTime(formattedDateTime);
        Object playDelay = programInfo.get("playDelay");
        Object startRow = programInfo.get("startRow");
        Object offset = programInfo.get("offset");
        tProgram.setPlayDelay(playDelay == null ?null:Integer.parseInt(playDelay.toString()));
        tProgram.setStartRow(startRow == null?null:Integer.parseInt(startRow.toString()));
        tProgram.setOffset(offset == null?null:Integer.parseInt(offset.toString()));
        save(tProgram);
        return tProgram.getId();
    }

    @Override
    public void addItemInProgram(ArrayList<HashMap<String, Object>> items) {
        tProgramMaterialService.addItemInProgram(items);
    }

    @Override
    public List<Map<String, Object>> getProgramList() {
        List<TProgram> programList = list();
        Set<Integer> programIdsSet = list().stream().map(new Function<TProgram, Integer>() {

            @Override
            public Integer apply(TProgram tProgram) {
                return tProgram.getId();
            }
        }).collect(Collectors.toSet());
        List<TProgramMaterial> materialIdsByProgramIds = tProgramMaterialService.getMaterialIdsByProgramIds(programIdsSet);
        HashMap<Integer, ArrayList<TProgramMaterial>> programIdMapMaterials = new HashMap<>();
        for (TProgramMaterial materialByProgramId : materialIdsByProgramIds) {
            materialByProgramId.setMedia(materialByProgramId.getFilepath());
            Integer plId = materialByProgramId.getPlId();
            ArrayList<TProgramMaterial> tProgramMaterials = programIdMapMaterials.get(plId);
            if (CollectionUtils.isEmpty(tProgramMaterials)) {
                tProgramMaterials = new ArrayList<>();
                programIdMapMaterials.put(plId, tProgramMaterials);
            }
            tProgramMaterials.add(materialByProgramId);
        }
        List<Map<String, Object>> programsMap = programList.stream().map(new Function<TProgram, Map<String, Object>>() {
            @Override
            public Map<String, Object> apply(TProgram tProgram) {
                String jsonStr = JSON.toJSONString(tProgram);  // 对象→JSON字符串
                Map<String, Object> map = JSON.parseObject(jsonStr, Map.class);
                map.put("program_name", tProgram.getProgramName());
                ArrayList<TProgramMaterial> tProgramMaterials = programIdMapMaterials.get(tProgram.getId());
                if (!CollectionUtils.isEmpty(tProgramMaterials)){
                    Integer duration = 0;
                    for (TProgramMaterial tProgramMaterial : tProgramMaterials) {
                        duration +=tProgramMaterial.getDuration() !=null?Integer.parseInt(tProgramMaterial.getDuration()):0;
                    }
                    Integer minute = duration / (1000 * 60);
                    Integer mSecond = duration % (1000 * 60);
                    map.put("pgDuration", minute + "分" + (mSecond / 1000) + "秒");
                    map.put("programs", tProgramMaterials);
                }

                if ("ppt".equals(tProgram.getProgramType())) {
                    String prefix = tProgram.getSubmitTime()
                            .replace(" ", "")
                            .replace("-", "")
                            .replace(":", "");
                    map.put("prefix", prefix);
                }
                return map;
            }
        }).collect(Collectors.toList());
        HashMap<String, Object> resMap = new HashMap<>();
        resMap.put("data", programsMap);
        return programsMap;
    }

    @Autowired
    private DefaultAssetsPathProvider pathProvider;


    @Override
    public String onDemandWithTrans(Map<String, Object> conditionMap) {
        System.out.println(conditionMap);
        ArrayList<HashMap<Integer, Object>> data = (ArrayList<HashMap<Integer, Object>>) conditionMap.get("data");
        HashMap<Integer, Object> programMap = data.get(0);
        Integer pl_id = (Integer) programMap.get("pl_id");
        String flvUrl = "http://" + SRSUtil.srsServer_ip + ":8080/live/p_" + pl_id + ".flv";

        List<TProgramMaterial> programIds = tProgramMaterialService.getMaterialIdsByProgramId(pl_id);
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (TProgramMaterial programId : programIds) {
                    // 1. 构建FFmpeg命令参数
                    List<String> command = new ArrayList<>();
                    command.add("ffmpeg");                          // FFmpeg可执行文件路径（需配置环境变量或写绝对路径）
                    command.add("-re");                             // 按实际帧率读取输入
                    command.add("-i");
                    command.add(pathProvider.getCurrentAssetsPath() + "/" + programId.getFilepath());
                    command.add("-c:v");
                    command.add("copy");                           // 视频流直接拷贝
                    command.add("-c:a");
                    command.add("aac");                            // 音频转AAC编码
                    command.add("-f");
                    command.add("flv");                            // 输出格式为FLV
                    command.add("rtmp://" + SRSUtil.srsServer_ip + ":1935/live/p_" + pl_id);      // RTMP推流地址
                    // 2. 执行命令
                    try {
                        ProcessBuilder builder = new ProcessBuilder(command);
                        builder.redirectErrorStream(true);         // 合并标准错误流到标准输出
                        Process process = builder.start();

                        // 3. 异步读取输出日志（避免阻塞）
                        new Thread(() -> {
                            try (var input = process.getInputStream()) {
                                byte[] buffer = new byte[1024];
                                while (input.read(buffer) != -1) {
                                    System.out.println(new String(buffer).trim());
                                }
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }).start();

                        int exitCode = process.waitFor();
                        System.out.println("推流结束，退出码：" + exitCode);
                    } catch (IOException | InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();


        return flvUrl;
    }

    @Override
    @Transactional
    public void deleteProgram(Map<String, Object> conditionMap) {
        ArrayList<HashMap<String, Object>> data = (ArrayList<HashMap<String, Object>>) conditionMap.get("data");
        HashMap<String, Object> pInfo = data.get(0);
        Integer pl_id = (Integer) pInfo.get("pl_id");
        removeById(pl_id);
        tProgramMaterialService.deleteByProgramId(pl_id);
    }

    @Override
    @Transactional
    public void deleteAllPrograms() {
        List<TProgram> list = list();
        List<Integer> programIds = list.stream().map(TProgram::getId).collect(Collectors.toList());
        tProgramMaterialService.deleteByProgramIds(programIds);
        remove(null);
    }
}
